"""统一抽象层中间件"""
from typing import Dict, Any, List, Optional
from dataclasses import dataclass
from datetime import datetime
from utils.logger import setup_application_logging
from utils.exceptions import ValidationException
# from utils.validators import validate_chain_type, validate_address, validate_transaction_data

@dataclass
class AccountInfo:
    """账户信息"""
    address: str
    balance: str
    nonce: Optional[int] = None
    public_key: Optional[str] = None
    private_key: Optional[str] = None
    
@dataclass
class BlockInfo:
    """区块信息"""
    block_number: int
    block_hash: str
    parent_hash: str
    timestamp: datetime
    transactions: List[str]
    miner: Optional[str] = None
    gas_used: Optional[int] = None
    gas_limit: Optional[int] = None
    
@dataclass
class TransactionInfo:
    """交易信息"""
    tx_hash: str
    from_address: str
    to_address: str
    value: str
    gas_price: Optional[str] = None
    gas_limit: Optional[int] = None
    gas_used: Optional[int] = None
    nonce: Optional[int] = None
    status: Optional[str] = None
    block_number: Optional[int] = None
    block_hash: Optional[str] = None
    timestamp: Optional[datetime] = None
    
@dataclass
class ContractInfo:
    """合约信息"""
    address: str
    bytecode: str
    abi: Optional[Dict[str, Any]] = None
    creator: Optional[str] = None
    creation_tx: Optional[str] = None
    
@dataclass
class ChainInfo:
    """区块链信息"""
    chain_id: str
    chain_name: str
    latest_block: int
    network_id: Optional[str] = None
    consensus: Optional[str] = None
    version: Optional[str] = None

class UnifiedAbstractionLayer:
    """统一抽象层类"""
    
    def __init__(self, app_config=None):
        """初始化统一抽象层"""
        # 延迟导入以避免循环导入
        from adapters.adapter_factory import AdapterFactory
        self.adapter_factory = AdapterFactory()
        self.logger = setup_application_logging()
        self._adapters = {}
        self.app_config = app_config
    
    def get_adapter(self, chain_type: str):
        """获取指定区块链类型的适配器"""
        try:
            # # validate_chain_type(chain_type)
            
            if chain_type not in self._adapters:
                # 从应用配置中获取适配器配置
                adapter_config = None
                if self.app_config and hasattr(self.app_config, 'SUPPORTED_CHAINS'):
                    adapter_config = self.app_config.SUPPORTED_CHAINS.get(chain_type)
                
                self._adapters[chain_type] = self.adapter_factory.create_adapter(chain_type, adapter_config)
            
            return self._adapters[chain_type]
            
        except Exception as e:
            self.logger.error(f"获取适配器失败: {str(e)}")
            raise
    
    def send_transaction(self, chain_type: str, transaction_data: Dict[str, Any]) -> Dict[str, Any]:
        """发送交易"""
        try:
            # # # validate_chain_type(chain_type)
            # validate_transaction_data(transaction_data)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.send_transaction(transaction_data)
            
            self.logger.info(f"交易发送成功: {chain_type}")
            return result
            
        except Exception as e:
            self.logger.error(f"发送交易失败: {str(e)}")
            raise
    
    def get_transaction(self, chain_type: str, tx_hash: str) -> Dict[str, Any]:
        """获取交易信息"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.get_transaction(tx_hash)
            
            return result
            
        except Exception as e:
            self.logger.error(f"获取交易失败: {str(e)}")
            raise
    
    def get_balance(self, chain_type: str, address: str) -> Dict[str, Any]:
        """获取账户余额"""
        try:
            # # # validate_chain_type(chain_type)
            # validate_address(address)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.get_balance(address)
            
            return result
            
        except Exception as e:
            self.logger.error(f"获取余额失败: {str(e)}")
            raise
    
    def deploy_contract(self, chain_type: str, contract_data: Dict[str, Any]) -> Dict[str, Any]:
        """部署智能合约"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.deploy_contract(contract_data)
            
            self.logger.info(f"合约部署成功: {chain_type}")
            return result
            
        except Exception as e:
            self.logger.error(f"部署合约失败: {str(e)}")
            raise
    
    def call_contract(self, chain_type: str, contract_address: str, method: str, params: List[Any] = None, **kwargs) -> Dict[str, Any]:
        """调用智能合约"""
        try:
            # # validate_chain_type(chain_type)
            # validate_address(contract_address)
            
            adapter = self.get_adapter(chain_type)
            
            # 对于XuperChain，直接调用同步方法
            if chain_type.lower() == 'xuperchain':
                result = adapter.call_contract(contract_address, method, params or [])
            elif chain_type.lower() == 'fisco_bcos':
                # FISCO BCOS特殊处理，支持可选参数
                import asyncio
                import concurrent.futures
                
                def run_async_in_thread(coro):
                    def run_in_thread():
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)
                        try:
                            return loop.run_until_complete(coro)
                        finally:
                            loop.close()
                    
                    with concurrent.futures.ThreadPoolExecutor() as executor:
                        future = executor.submit(run_in_thread)
                        return future.result()
                
                # 为FISCO BCOS调用传递额外参数
                if method == "set" and len(params or []) >= 2:
                    # 构建参数字典，只传递非None的参数
                    call_kwargs = {}
                    # contract_address通过位置参数传递，如果为空则不传递让适配器使用默认值
                    if contract_address:
                        call_kwargs['contract_address'] = contract_address
                    if kwargs.get('user_address') is not None:
                        call_kwargs['user_address'] = kwargs.get('user_address')
                    
                    result = run_async_in_thread(adapter.call_simple_storage_set(
                        key=params[0], 
                        value=params[1],
                        **call_kwargs
                    ))
                elif method == "get" and len(params or []) >= 1:
                    # 使用call_contract方法而不是直接调用call_simple_storage_get
                    result = run_async_in_thread(adapter.call_contract(contract_address, method, params or [], **kwargs))
                else:
                    result = run_async_in_thread(adapter.call_contract(contract_address, method, params or [], **kwargs))
            elif chain_type.lower() == 'chainmaker':
                # ChainMaker特殊处理，需要确保params是字典格式
                import asyncio
                import concurrent.futures
                
                def run_async_in_thread(coro):
                    def run_in_thread():
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)
                        try:
                            return loop.run_until_complete(coro)
                        finally:
                            loop.close()
                    
                    with concurrent.futures.ThreadPoolExecutor() as executor:
                        future = executor.submit(run_in_thread)
                        return future.result()
                
                # 确保params是字典格式
                if isinstance(params, dict):
                    chainmaker_params = params
                elif isinstance(params, list) and len(params) > 0:
                    # 如果是列表，尝试转换为字典
                    if method == 'set' and len(params) >= 2:
                        chainmaker_params = {'key': params[0], 'value': params[1]}
                    elif method == 'get' and len(params) >= 1:
                        chainmaker_params = {'key': params[0]}
                    else:
                        chainmaker_params = {}
                else:
                    chainmaker_params = {}
                
                result = run_async_in_thread(adapter.call_contract(contract_address, method, chainmaker_params, **kwargs))
            else:
                # 其他链可能仍然是异步的，需要在线程中运行
                import asyncio
                import concurrent.futures
                
                def run_async_in_thread(coro):
                    def run_in_thread():
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)
                        try:
                            return loop.run_until_complete(coro)
                        finally:
                            loop.close()
                    
                    with concurrent.futures.ThreadPoolExecutor() as executor:
                        future = executor.submit(run_in_thread)
                        return future.result()
                
                result = run_async_in_thread(adapter.call_contract(contract_address, method, params or [], **kwargs))
            
            # 统一get方法的返回格式
            if method == 'get':
                self.logger.info(f"Processing get method for {chain_type}, result: {result}")
                # 为所有底链统一返回格式为 {"data": {"value": "xxx"}}
                if chain_type.lower() == 'xuperchain':
                    # XuperChain已经是标准格式，直接返回
                    self.logger.info(f"XuperChain result returned as-is")
                    return result
                elif chain_type.lower() == 'fisco_bcos':
                    # FISCO BCOS返回格式: {"data": ["xxx"], "requestId": "...", "success": true}
                    # 转换为标准格式
                    if isinstance(result, dict) and 'data' in result:
                        # FISCO BCOS的data是一个数组，取第一个元素作为value
                        data_value = result['data']
                        if isinstance(data_value, list) and len(data_value) > 0:
                            value = data_value[0]
                        else:
                            value = data_value
                        formatted_result = {
                            'data': {'value': value},
                            'requestId': result.get('requestId'),
                            'success': result.get('success', True)
                        }
                        self.logger.info(f"FISCO BCOS result formatted: {formatted_result}")
                        return formatted_result
                elif chain_type.lower() == 'chainmaker':
                    # ChainMaker返回格式: {"data": {"contract_result": {"result": "xxx"}}}
                    # 转换为标准格式
                    if isinstance(result, dict) and 'data' in result:
                        contract_result = result['data'].get('contract_result', {})
                        value = contract_result.get('result', '')
                        return {
                            'data': {'value': value},
                            'requestId': result.get('requestId'),
                            'success': result.get('success', True)
                        }
                elif chain_type.lower() == 'jdchain':
                    # JDChain返回格式: {"success": true, "value": "xxx", "message": "..."}
                    # 转换为标准格式
                    if isinstance(result, dict) and 'value' in result:
                        return {
                            'data': {'value': result['value']},
                            'requestId': result.get('requestId'),
                            'success': result.get('success', True)
                        }
                elif chain_type.lower() == 'thanos':
                    # Thanos直接返回字符串值
                    # 转换为标准格式
                    if isinstance(result, str):
                        return {
                            'data': {'value': result},
                            'requestId': None,
                            'success': True
                        }
                    elif isinstance(result, dict) and 'value' in result:
                        return {
                            'data': {'value': result['value']},
                            'requestId': result.get('requestId'),
                            'success': result.get('success', True)
                        }
            
            return result
            
        except Exception as e:
            self.logger.error(f"调用合约失败: {str(e)}")
            raise
    
    def get_block(self, chain_type: str, block_identifier: str) -> Dict[str, Any]:
        """获取区块信息"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.get_block(block_identifier)
            
            return result
            
        except Exception as e:
            self.logger.error(f"获取区块失败: {str(e)}")
            raise
    
    def get_chain_info(self, chain_type: str) -> Dict[str, Any]:
        """获取区块链信息"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            
            # 优先使用XuperChain适配器的同步版本方法
            if chain_type.lower() == 'xuperchain' and hasattr(adapter, 'get_chain_info_sync'):
                result = adapter.get_chain_info_sync()
            elif chain_type.lower() == 'chainmaker' and hasattr(adapter, 'get_chain_info_sync'):
                # ChainMaker的get_chain_info_sync是异步方法，需要特殊处理
                import asyncio
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        # 如果事件循环正在运行，创建一个新的任务
                        import concurrent.futures
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(asyncio.run, adapter.get_chain_info_sync())
                            result = future.result()
                    else:
                        # 如果没有运行的事件循环，直接运行
                        result = loop.run_until_complete(adapter.get_chain_info_sync())
                except RuntimeError:
                    # 如果没有事件循环，创建一个新的
                    result = asyncio.run(adapter.get_chain_info_sync())
            elif hasattr(adapter, 'get_chain_info_sync'):
                result = adapter.get_chain_info_sync()
            else:
                # 如果没有同步版本，尝试运行异步版本
                import asyncio
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        # 如果事件循环正在运行，创建一个新的任务
                        import concurrent.futures
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(asyncio.run, adapter.get_chain_info())
                            result = future.result()
                    else:
                        # 如果没有运行的事件循环，直接运行
                        result = loop.run_until_complete(adapter.get_chain_info())
                except RuntimeError:
                    # 如果没有事件循环，创建一个新的
                    result = asyncio.run(adapter.get_chain_info())
            
            # 将ChainInfo对象转换为字典
            if hasattr(result, '__dict__'):
                return result.__dict__
            else:
                return result
            
        except Exception as e:
            self.logger.error(f"获取链信息失败: {str(e)}")
            raise
    
    def create_account(self, chain_type: str) -> Dict[str, Any]:
        """创建账户"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.create_account()
            
            self.logger.info(f"账户创建成功: {chain_type}")
            return result
            
        except Exception as e:
            self.logger.error(f"创建账户失败: {str(e)}")
            raise
    
    def get_supported_chains(self) -> List[str]:
        """获取支持的区块链类型"""
        return self.adapter_factory.get_supported_chains()
    
    def get_latest_block(self, chain_type: str, with_transactions: bool = False) -> Dict[str, Any]:
        """获取最新区块"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            
            # 检查适配器是否有同步版本的get_latest_block方法
            if hasattr(adapter, 'get_latest_block_sync'):
                result = adapter.get_latest_block_sync()
            else:
                # 如果没有同步版本，尝试运行异步版本
                import asyncio
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        # 如果事件循环正在运行，创建一个新的任务
                        import concurrent.futures
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(asyncio.run, adapter.get_latest_block())
                            result = future.result()
                    else:
                        # 如果没有运行的事件循环，直接运行
                        result = loop.run_until_complete(adapter.get_latest_block())
                except RuntimeError:
                    # 如果没有事件循环，创建一个新的
                    result = asyncio.run(adapter.get_latest_block())
            
            # 将BlockInfo对象转换为字典
            if hasattr(result, '__dict__'):
                block_dict = result.__dict__.copy()
            else:
                block_dict = result
            
            # 处理时间戳格式
            if 'timestamp' in block_dict and hasattr(block_dict['timestamp'], 'timestamp'):
                try:
                    timestamp_value = block_dict['timestamp'].timestamp()
                    self.logger.info(f"时间戳转换: {block_dict['timestamp']} -> {timestamp_value}")
                    block_dict['timestamp'] = int(timestamp_value)
                except Exception as ts_error:
                    self.logger.error(f"时间戳转换失败: {ts_error}, 原始时间戳: {block_dict['timestamp']}")
                    # 使用当前时间作为备用
                    import time
                    block_dict['timestamp'] = int(time.time())
            
            # 如果需要交易详情但当前没有，可以添加模拟数据
            if with_transactions and ('transactions' not in block_dict or not block_dict['transactions']):
                block_dict['transactions'] = []
                block_dict['transaction_count'] = 0
            
            return block_dict
            
        except Exception as e:
            self.logger.error(f"获取最新区块失败: {str(e)}")
            raise
    
    def get_block_by_number(self, chain_type: str, block_number: int, with_transactions: bool = False) -> Dict[str, Any]:
        """根据区块号获取区块信息"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            
            # 检查适配器是否有同步版本的get_block方法
            if hasattr(adapter, 'get_block_sync'):
                result = adapter.get_block_sync(block_number)
            elif hasattr(adapter, 'get_block'):
                # 如果没有同步版本，尝试运行异步版本
                import asyncio
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        # 如果事件循环正在运行，创建一个新的任务
                        import concurrent.futures
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(asyncio.run, adapter.get_block(block_number))
                            result = future.result()
                    else:
                        # 如果没有运行的事件循环，直接运行
                        result = loop.run_until_complete(adapter.get_block(block_number))
                except RuntimeError:
                    # 如果没有事件循环，创建一个新的
                    result = asyncio.run(adapter.get_block(block_number))
            else:
                raise AttributeError(f"Adapter for {chain_type} does not have get_block method")
            
            # 将BlockInfo对象转换为字典
            if hasattr(result, '__dict__'):
                block_dict = result.__dict__.copy()
            else:
                block_dict = result
            
            # 处理时间戳格式
            if 'timestamp' in block_dict and hasattr(block_dict['timestamp'], 'timestamp'):
                try:
                    timestamp_value = block_dict['timestamp'].timestamp()
                    self.logger.info(f"时间戳转换: {block_dict['timestamp']} -> {timestamp_value}")
                    block_dict['timestamp'] = int(timestamp_value)
                except Exception as ts_error:
                    self.logger.error(f"时间戳转换失败: {ts_error}, 原始时间戳: {block_dict['timestamp']}")
                    # 使用当前时间作为备用
                    import time
                    block_dict['timestamp'] = int(time.time())
            
            # 如果需要交易详情但当前没有，可以添加模拟数据
            if with_transactions and ('transactions' not in block_dict or not block_dict['transactions']):
                block_dict['transactions'] = []
                block_dict['transaction_count'] = 0
            
            return block_dict
            
        except Exception as e:
            self.logger.error(f"根据区块号获取区块失败: {str(e)}")
            raise
    
    def get_block_by_hash(self, chain_type: str, block_hash: str, with_transactions: bool = False) -> Dict[str, Any]:
        """根据区块哈希获取区块信息"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            
            # 检查适配器是否有同步版本的get_block方法
            if hasattr(adapter, 'get_block_sync'):
                result = adapter.get_block_sync(block_hash)
            elif hasattr(adapter, 'get_block'):
                # 如果没有同步版本，尝试运行异步版本
                import asyncio
                try:
                    loop = asyncio.get_event_loop()
                    if loop.is_running():
                        # 如果事件循环正在运行，创建一个新的任务
                        import concurrent.futures
                        with concurrent.futures.ThreadPoolExecutor() as executor:
                            future = executor.submit(asyncio.run, adapter.get_block(block_hash))
                            result = future.result()
                    else:
                        # 如果没有运行的事件循环，直接运行
                        result = loop.run_until_complete(adapter.get_block(block_hash))
                except RuntimeError:
                    # 如果没有事件循环，创建一个新的
                    result = asyncio.run(adapter.get_block(block_hash))
            else:
                raise AttributeError(f"Adapter for {chain_type} does not have get_block method")
            
            # 将BlockInfo对象转换为字典
            if hasattr(result, '__dict__'):
                block_dict = result.__dict__.copy()
            else:
                block_dict = result
            
            # 处理时间戳格式
            if 'timestamp' in block_dict and hasattr(block_dict['timestamp'], 'timestamp'):
                try:
                    timestamp_value = block_dict['timestamp'].timestamp()
                    self.logger.info(f"时间戳转换: {block_dict['timestamp']} -> {timestamp_value}")
                    block_dict['timestamp'] = int(timestamp_value)
                except Exception as ts_error:
                    self.logger.error(f"时间戳转换失败: {ts_error}, 原始时间戳: {block_dict['timestamp']}")
                    # 使用当前时间作为备用
                    import time
                    block_dict['timestamp'] = int(time.time())
            
            # 如果需要交易详情但当前没有，可以添加模拟数据
            if with_transactions and ('transactions' not in block_dict or not block_dict['transactions']):
                block_dict['transactions'] = []
                block_dict['transaction_count'] = 0
            
            return block_dict
            
        except Exception as e:
            self.logger.error(f"根据区块哈希获取区块失败: {str(e)}")
            raise
    
    def health_check(self, chain_type: str) -> Dict[str, Any]:
        """健康检查"""
        try:
            # # validate_chain_type(chain_type)
            
            adapter = self.get_adapter(chain_type)
            result = adapter.health_check()
            
            return {
                'chain_type': chain_type,
                'status': 'healthy' if result.get('success', False) else 'unhealthy',
                'details': result
            }
            
        except Exception as e:
            self.logger.error(f"健康检查失败: {str(e)}")
            return {
                'chain_type': chain_type,
                'status': 'unhealthy',
                'error': str(e)
            }